package com.zcxy.fast.mybatisExtend;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zcxy.fast.bean.BaseEntity;
import com.zcxy.fast.bean.PageQuery;
import com.zcxy.fast.bean.Response;
import com.zcxy.fast.bean.SysUser;
import com.zcxy.fast.constant.CommonConstant;
import com.zcxy.fast.exception.BusinessException;
import com.zcxy.fast.utils.JwtUtil;
import org.apache.ibatis.binding.MapperMethod;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.*;

/**
 * @author zcc
 * @version 1.0.0
 * @ClassName baseService.java
 * @Description TODO
 * @createTime 2019年12月04日 11:39:00
 */
public class BaseServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> {

    public static boolean isEmpty(Object obj) {
        if (obj == null) {
            return true;
        }
        if ((obj instanceof List)) {
            return ((List) obj).size() == 0;
        }
        if ((obj instanceof String)) {
            return ((String) obj).trim().equals("");//判断Stirng类型的对象是否为空，一个是和null对比，一个是点equal("")
        }
        return false;
    }

    /**
     * 分页查询简化
     *
     * @param tPageQuery
     * @return
     */
    public Response<IPage<T>> pageQuery(PageQuery<T> tPageQuery, QueryWrapper<T> queryWrapper) {
        Response<IPage<T>> Response = new Response<IPage<T>>();
        Page<T> page = new Page<T>(tPageQuery.getPageNo(), tPageQuery.getPageSize());
        Response.setSuccess(true);
        IPage<T> pageList = page(page, queryWrapper);
        Response.setResult(pageList);
        return Response;
    }

    public List<T> listByEntity(T t) {
        QueryWrapper queryWrapper = new QueryWrapper(t);
        return baseMapper.selectList(queryWrapper);
    }

    public T selectOneByEntity(T t) {
        QueryWrapper queryWrapper = new QueryWrapper(t);
        List<T> ts = baseMapper.selectList(queryWrapper);
        BaseEntity baseEntity = new BaseEntity();
        if (ts.size() > 0) {
            return ts.get(0);
        }
        return null;
    }



    /**
     * 多属性(组合属性)校验修改重复
     *
     * @param valiteConditions         属性名称及值组合数组对象
     *
     */

    public void validFiledExist(LambdaValiteCondition valiteConditions,Boolean matchCase) {
        T t = createT();
        // 调用set方法
        try {
            QueryWrapper queryWrapper = new QueryWrapper(t);
            Map<String, Object> cons=valiteConditions.getFiledConsumer();
            if(CollectionUtil.isNotEmpty(cons)){
                for(String key:cons.keySet()){
                    String filedName = key;
                    Object filedValue = cons.get(key);
                    if (isEmpty(filedValue)) {
                        continue;
                    }
                    if(matchCase){
                        Field fieldValid = t.getClass().getDeclaredField(filedName);
                        Assert.notNull(fieldValid, "需要校验重复的字段不存在，请检查传入参数");
                        fieldValid.setAccessible(true);
                        fieldValid.set(t, filedValue);
                        fieldValid.setAccessible(false);
                    }else{
                        queryWrapper.likeLeft(StringUtils.camelToUnderline(filedName),filedValue);
                        queryWrapper.likeRight(StringUtils.camelToUnderline(filedName),filedValue);
                    }
                }
            }
            Map<String, Object> exsitsCons=valiteConditions.getExcludeConsumer();
            if(CollectionUtil.isNotEmpty(exsitsCons)){
                for(String key:exsitsCons.keySet()){
                    String filedName = key;
                    Object filedValue = exsitsCons.get(key);
                    if (isEmpty(filedValue)) {
                        continue;
                    }
                    queryWrapper.notIn(filedName.replaceAll("[A-Z]", "_$0").toLowerCase(), filedValue);
                }
            }
            int count = baseMapper.selectCount(queryWrapper);
            if (count > 0) {
                throw new BusinessException(valiteConditions.getErrInfo());
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            throw new BusinessException("属性不存在");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 多属性(组合属性)校验修改重复(不区分大小写)
     *
     * @param valiteConditions
     *
     */

    public void validFiledExist(LambdaValiteCondition valiteConditions) {
        validFiledExist(valiteConditions,true);
    }

    public T createT() {
        T t = null;
        try {
            ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
            Class<T> tClass = (Class<T>) parameterizedType.getActualTypeArguments()[1];
            t = tClass.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return t;
    }

    public void insertDefualtValue(T i, SysUser sysUser) {
        insertDefualtValue(i, sysUser, null);
    }

    public void insertDefualtValue(T i, SysUser sysUser, Field[] fields) {
        try {
            if (fields == null)
                fields = ReflectUtil.getFields(i.getClass());
            for (Field field : fields) {
                if (!("createBy".equals(field.getName()) || "createTime".equals(field.getName()) || "updateTime".equals(field.getName()) || "updateBy".equals(field.getName()) || "delFlag".equals(field.getName()))) {
                    continue;
                }
                log.debug("------field.name------" + field.getName());

                // 获取当前的用户
                if ("createBy".equals(field.getName())) {
                    field.setAccessible(true);
                    Object local_createBy = field.get(i);
                    field.setAccessible(false);
                    if (local_createBy == null || local_createBy.equals("")) {
                        String createBy = "admin";
                        if (sysUser != null) {
                            // 登录账号
                            createBy = sysUser.getLoginName();
                        }
                        if (StringUtils.isNotEmpty(createBy)) {
                            field.setAccessible(true);
                            field.set(i, createBy);
                            field.setAccessible(false);
                        }
                    }
                }
                // 注入创建时间
                else if ("createTime".equals(field.getName())) {
                    field.setAccessible(true);
                    Object local_createDate = field.get(i);
                    field.setAccessible(false);
                    if (local_createDate == null || local_createDate.equals("")) {
                        field.setAccessible(true);
                        field.set(i, new Date());
                        field.setAccessible(false);
                    }
                } else if ("updateBy".equals(field.getName())) {
                    field.setAccessible(true);
                    try {
                        Object local_updateBy = field.get(i);
                        field.setAccessible(false);

                        String updateBy = "admin";
                        if (sysUser != null) {
                            // 登录账号
                            updateBy = sysUser.getLoginName();
                        }
                        if (StringUtils.isNotEmpty(updateBy)) {
                            field.setAccessible(true);
                            field.set(i, updateBy);
                            field.setAccessible(false);
                        }

                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                } else if ("updateTime".equals(field.getName())) {
                    field.setAccessible(true);
                    try {
                        field.set(i, new Date());
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    field.setAccessible(false);
                } else if ("delFlag".equals(field.getName())) {
                    field.setAccessible(true);
                    Object local_delFlag = field.get(i);
                    field.setAccessible(false);
                    if (local_delFlag == null || local_delFlag.equals("")) {
                        field.setAccessible(true);
                        field.set(i, CommonConstant.DEL_FLAG_1);
                        field.setAccessible(false);
                    }
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            throw new BusinessException(e.getMessage());
        }
    }

    @Override
    public boolean saveBatch(Collection<T> entityList) {
        if (CollectionUtil.isEmpty(entityList)) return true;
        SysUser sysUser = JwtUtil.getLoginUser();
        Object t = entityList.toArray()[0];
        Field[] fields = ReflectUtil.getFields(t.getClass());
        entityList.stream().forEach(i -> {
            insertDefualtValue(i, sysUser, fields);
        });
        return super.saveBatch(entityList);
    }

    @Override
    public boolean saveOrUpdateBatch(Collection<T> entityList) {
        if (CollectionUtil.isEmpty(entityList)) return true;

        SysUser sysUser = JwtUtil.getLoginUser();
        Object t = entityList.toArray()[0];
        Field[] fields = ReflectUtil.getFields(t.getClass());
        entityList.stream().forEach(i -> {
            insertDefualtValue(i, sysUser, fields);
        });

        com.baomidou.mybatisplus.core.toolkit.Assert.notEmpty(entityList, "error: entityList must not be empty", new Object[0]);
        Class<?> cls = this.currentModelClass();
        TableInfo tableInfo = TableInfoHelper.getTableInfo(cls);
        com.baomidou.mybatisplus.core.toolkit.Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!", new Object[0]);
        String keyProperty = tableInfo.getKeyProperty();
        com.baomidou.mybatisplus.core.toolkit.Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!", new Object[0]);
        int size = entityList.size();

        this.executeBatch((sqlSession) -> {
            int i = 1;
            for(Iterator var8 = entityList.iterator(); var8.hasNext(); ++i) {
                T entity = (T)var8.next();
                Object idVal = ReflectionKit.getMethodValue(cls, entity, keyProperty);
                if (!StringUtils.checkValNull(idVal) ) {
                    MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
                    param.put("et", entity);
                    sqlSession.update(this.sqlStatement(SqlMethod.UPDATE_BY_ID), param);
                } else {
                    sqlSession.insert(this.sqlStatement(SqlMethod.INSERT_ONE), entity);
                }

                if (i % 1000 == 0 || i == size) {
                    sqlSession.flushStatements();
                }
            }

        });
        return true;
    }



    @Override
    public boolean save(T entity) {
        SysUser sysUser = JwtUtil.getLoginUser();
        insertDefualtValue(entity, sysUser);
        return super.save(entity);
    }

    @Override
    public boolean saveOrUpdate(T entity) {
        SysUser sysUser = JwtUtil.getLoginUser();
        insertDefualtValue(entity, sysUser);
        return super.saveOrUpdate(entity);
    }


    public static void main(String[] args) {
        List<SysUser> sysUsers = new ArrayList<>();
        SysUser sysUser = new SysUser();
        sysUsers.add(sysUser);
        saveBatchss(sysUsers);
    }

    public static <T> void saveBatchss(Collection<T> entityList) {
        Object t = entityList.toArray()[0];

        Field[] fields = ReflectUtil.getFields(t.getClass());
        for (Field field : fields) {
            System.out.println(field.getName());
        }

    }
}
